using System;
using System.Diagnostics;
using System.Collections.Generic;
using Xeralabs.Globalization;


namespace Xeralabs.Common.Internals 
{
	/// <summary>
	/// Describes what to do if a key is already in the tree when doing an
	/// insertion.
	/// </summary>
	internal enum DuplicatePolicy { 
		InsertFirst,               // Insert a new node before duplicates
		InsertLast,               // Insert a new node after duplicates
		ReplaceFirst,            // Replace the first of the duplicate nodes
		ReplaceLast,            // Replace the last of the duplicate nodes
		DoNothing                // Do nothing to the tree
	};

	/// <summary>
	/// The base implementation for various collections classes that use Red-Black trees
	/// as part of their implementation. This class should not (and can not) be 
	/// used directly by end users; it's only for internal use by the collections package.
	/// </summary>
	/// <remarks>
	/// The Red-Black tree manages items of type T, and uses a IComparer&lt;T&gt; that
	/// compares items to sort the tree. Multiple items can compare equal and be stored
	/// in the tree. Insert, Delete, and Find operations are provided in their full generality;
	/// all operations allow dealing with either the first or last of items that compare equal. 
	///</remarks>
	[Serializable]
	internal class RedBlackTree<T>: IEnumerable<T> {
		private readonly IComparer<T> comparer;			// interface for comparing elements, only Compare is used.
		private Node root;					// The root of the tree. Can be null when tree is empty.
		private int count;						// The count of elements in the tree.

		private int changeStamp;        // An integer that is changed every time the tree structurally changes.
														// Used so that enumerations throw an exception if the tree is changed
														// during enumeration.

		private Node[] stack;               // A stack of nodes. This is cached locally to avoid constant re-allocated it.

		/// <summary>
		/// Create an array of Nodes big enough for any path from top 
		/// to bottom. This is cached, and reused from call-to-call, so only one
		/// can be around at a time per tree.
		/// </summary>
		/// <returns>The node stack.</returns>
		private Node[] GetNodeStack()
		{
			// Maximum depth needed is 2 * lg count + 1.
			int maxDepth;
			if (count < 0x400)
				maxDepth = 21;
			else if (count < 0x10000)
				maxDepth = 41;
			else
				maxDepth = 65;

			if (stack == null || stack.Length < maxDepth)
				stack = new Node[maxDepth];

			return stack;
		}

		/// <summary>
		/// The class that is each node in the red-black tree.
		/// </summary>
		[Serializable]
		private class Node {
			public Node left, right;
			public T item;

			private const uint REDMASK = 0x80000000;
			private uint count;

			/// <summary>
			/// Is this a red node?
			/// </summary>
			public bool IsRed {
				get { return (count & REDMASK) != 0; }
				set { 
					if (value) 
						count |= REDMASK; 
					else
						count &= ~REDMASK;
				}
			}

			/// <summary>
			/// Get or set the Count field -- a 31-bit field
			/// that holds the number of nodes at or below this
			/// level.
			/// </summary>
			public int Count
			{
				get { return (int)(count & ~REDMASK); }
				set { count = (count & REDMASK) | (uint)value; }
			}

			/// <summary>
			/// Add one to the Count.
			/// </summary>
			public void IncrementCount()
			{
				++count;
			}

			/// <summary>
			/// Subtract one from the Count. The current
			/// Count must be non-zero.
			/// </summary>
			public void DecrementCount()
			{
				Debug.Assert(Count != 0);
				--count;
			}

			/// <summary>
			/// Clones a node and all its descendants.
			/// </summary>
			/// <returns>The cloned node.</returns>
			public Node Clone()
			{
				Node newNode = new Node();
				newNode.item = item;

				newNode.count = count;

				if (left != null)
					newNode.left = left.Clone();

				if (right != null)
					newNode.right = right.Clone();

				return newNode;
			}
		}

		/// <summary>
		/// Must be called whenever there is a structural change in the tree. Causes
		/// changeStamp to be changed, which causes any in-progress enumerations
		/// to throw exceptions.
		/// </summary>
		internal void StopEnumerations()
		{
			++changeStamp;
		}

		/// <summary>
		/// Checks the given stamp against the current change stamp. If different, the
		/// collection has changed during enumeration and an InvalidOperationException
		/// must be thrown
		/// </summary>
		/// <param name="startStamp">changeStamp at the start of the enumeration.</param>
		private void CheckEnumerationStamp(int startStamp)
		{
			if (startStamp != changeStamp) {
				throw new InvalidOperationException(Strings.ChangeDuringEnumeration);
			}
		}

		/// <summary>
		/// Initialize a red-black tree, using the given interface instance to compare elements. Only
		/// Compare is used on the IComparer interface.
		/// </summary>
		/// <param name="comparer">The IComparer&lt;T&gt; used to sort keys.</param>
		public RedBlackTree(IComparer<T> comparer) {
			this.comparer = comparer;
			this.count = 0;
			this.root = null;
		}

		/// <summary>
		/// Returns the number of elements in the tree.
		/// </summary>
		public int ElementCount {
			get {
				return count;
			}
		}

		/// <summary>
		/// Clone the tree, returning a new tree containing the same items. Should
		/// take O(N) take.
		/// </summary>
		/// <returns>Clone version of this tree.</returns>
		public RedBlackTree<T> Clone()
		{
			RedBlackTree<T> newTree = new RedBlackTree<T>(comparer);
			newTree.count = this.count;
			if (this.root != null)
				newTree.root = this.root.Clone();
			return newTree;
		}

		/// <summary>
		/// Finds the key in the tree. If multiple items in the tree have
		/// compare equal to the key, finds the first or last one. Optionally replaces the item
		/// with the one searched for.
		/// </summary>
		/// <param name="key">Key to search for.</param>
		/// <param name="findFirst">If true, find the first of duplicates, else finds the last of duplicates.</param>
		/// <param name="replace">If true, replaces the item with key (if function returns true)</param>
		/// <param name="item">Returns the found item, before replacing (if function returns true).</param>
		/// <returns>True if the key was found.</returns>
		public bool Find(T key, bool findFirst, bool replace, out T item) {
			Node current = root;			// current search location in the tree
			Node found = null;			// last node found with the key, or null if none.
			
			while (current != null) {
				int compare = comparer.Compare(key, current.item);

				if (compare < 0) {
					current = current.left;
				}
				else if (compare > 0) {
					current = current.right;
				}
				else {
					// Go left/right on equality to find first/last of elements with this key.
					Debug.Assert(compare == 0);
					found = current;
					if (findFirst)
						current = current.left;
					else
						current = current.right;
				}
			}

			if (found != null) {
				item = found.item;
				if (replace)
					found.item = key;
				return true;
			}
			else {
				item = default(T);	
				return false;
			}
		}

		/// <summary>
		/// Finds the index of the key in the tree. If multiple items in the tree have
		/// compare equal to the key, finds the first or last one. 
		/// </summary>
		/// <param name="key">Key to search for.</param>
		/// <param name="findFirst">If true, find the first of duplicates, else finds the last of duplicates.</param>
		/// <returns>Index of the item found if the key was found, -1 if not found.</returns>
		public int FindIndex(T key, bool findFirst)
		{
			T dummy;
			if (findFirst)
				return FirstItemInRange(EqualRangeTester(key), out dummy);
			else
				return LastItemInRange(EqualRangeTester(key), out dummy);
		}

		/// <summary>
		/// Find the item at a particular index in the tree.
		/// </summary>
		/// <param name="index">The zero-based index of the item. Must be &gt;= 0 and &lt; Count.</param>
		/// <returns>The item at the particular index.</returns>
		public T GetItemByIndex(int index)
		{
			if (index < 0 || index >= count)
				throw new ArgumentOutOfRangeException("index");

			Node current = root;			// current search location in the tree

			for (; ; ) {
				int leftCount;

				if (current.left != null) 
					leftCount = current.left.Count;
				else 
					leftCount = 0;

				if (leftCount > index)
					current = current.left;
				else if (leftCount == index)
					return current.item;
				else {
					index -= leftCount + 1;
					current = current.right;
				}
			}
		}

		/// <summary>
		/// Insert a new node into the tree, maintaining the red-black invariants.
		/// </summary>
		/// <remarks>Algorithm from Sedgewick, "Algorithms".</remarks>
		/// <param name="item">The new item to insert</param>
		/// <param name="dupPolicy">What to do if equal item is already present.</param>
		/// <param name="previous">If false, returned, the previous item.</param>
		/// <returns>false if duplicate exists, otherwise true.</returns>
		public bool Insert(T item, DuplicatePolicy dupPolicy, out T previous) {
			Node node = root;
			Node parent = null, gparent = null, ggparent = null;	// parent, grand, a great-grantparent of node.
			bool wentLeft = false, wentRight = false;				// direction from parent to node.
			bool rotated;
			Node duplicateFound = null;

			// The tree may be changed.
			StopEnumerations();

			// We increment counts on the way down the tree. If we end up not inserting an items due
			// to a duplicate, we need a stack to adjust the counts back. We don't need the stack if the duplicate
			// policy means that we will always do an insertion.
			bool needStack = !((dupPolicy == DuplicatePolicy.InsertFirst) || (dupPolicy == DuplicatePolicy.InsertLast));
			Node[] nodeStack = null;
			int nodeStackPtr = 0;  // first free item on the stack.
			if (needStack) 
				nodeStack = GetNodeStack();

			while (node != null) {
				// If we find a node with two red children, split it so it doesn't cause problems
				// when inserting a node.
				if (node.left != null && node.left.IsRed && node.right != null && node.right.IsRed) {
					node = InsertSplit(ggparent, gparent, parent, node, out rotated);

					if (needStack && rotated) {
						nodeStackPtr -= 2;
						if (nodeStackPtr < 0)
							nodeStackPtr = 0;
					}
				}

				// Keep track of parent, grandparent, great-grand parent.
				ggparent = gparent; gparent = parent; parent = node;

				// Compare the key and the node. 
				int compare = comparer.Compare(item, node.item);

				if (compare == 0) {
					// Found a node with the data already. Check duplicate policy.
					if (dupPolicy == DuplicatePolicy.DoNothing) {
						previous = node.item;

						// Didn't insert after all. Return counts back to their previous value.
						for (int i = 0; i < nodeStackPtr; ++i)
							nodeStack[i].DecrementCount();

						return false;
					}
					else if (dupPolicy == DuplicatePolicy.InsertFirst || dupPolicy == DuplicatePolicy.ReplaceFirst) {
						// Insert first by treating the key as less than nodes in the tree.
						duplicateFound = node;
						compare = -1;
					}
					else {
						Debug.Assert(dupPolicy == DuplicatePolicy.InsertLast || dupPolicy == DuplicatePolicy.ReplaceLast);
						// Insert last by treating the key as greater than nodes in the tree.
						duplicateFound = node;
						compare = 1;
					}
				}

				Debug.Assert(compare != 0);

				node.IncrementCount();
				if (needStack)
					nodeStack[nodeStackPtr++] = node;

				// Move to the left or right as needed to find the insertion point.
				if (compare < 0) {
					node = node.left;
					wentLeft = true; wentRight = false;
				}
				else {
					node = node.right;
					wentRight = true; wentLeft = false;
				}
			}

			if (duplicateFound != null) {
				previous = duplicateFound.item;

				// Are we replacing instread of inserting?
				if (dupPolicy == DuplicatePolicy.ReplaceFirst || dupPolicy == DuplicatePolicy.ReplaceLast) {
					duplicateFound.item = item;

					// Didn't insert after all. Return counts back to their previous value.
					for (int i = 0; i < nodeStackPtr; ++i)
						nodeStack[i].DecrementCount();

					return false;
				}
			}
			else {
				previous = default(T);
			}

			// Create a new node.
			node = new Node();
			node.item = item;
			node.Count = 1;

			// Link the node into the tree.
			if (wentLeft) 
				parent.left = node;
			else if (wentRight)
				parent.right = node;
			else {
				Debug.Assert(root == null);
				root = node;
			}

			// Maintain the red-black policy.
			InsertSplit(ggparent, gparent, parent, node, out rotated);

			// We've added a node to the tree, so update the count.
			count += 1;

			return (duplicateFound == null);
		}

		/// <summary>
		/// Split a node with two red children (a 4-node in the 2-3-4 tree formalism), as
		/// part of an insert operation.
		/// </summary>
		/// <param name="ggparent">great grand-parent of "node", can be null near root</param>
		/// <param name="gparent">grand-parent of "node", can be null near root</param>
		/// <param name="parent">parent of "node", can be null near root</param>
		/// <param name="node">Node to split, can't be null</param>
		/// <param name="rotated">Indicates that rotation(s) occurred in the tree.</param>
		/// <returns>Node to continue searching from.</returns>
		private Node InsertSplit(Node ggparent, Node gparent, Node parent, Node node, out bool rotated) {
			if (node != root)
				node.IsRed = true;
			if (node.left != null)
				node.left.IsRed = false;
			if (node.right != null)
				node.right.IsRed = false;

			if (parent != null && parent.IsRed) {
				// Since parent is red, gparent can't be null (root is always black). ggparent
				// might be null, however.
				Debug.Assert(gparent != null);

				// if links from gparent and parent are opposite (left/right or right/left),
				// then rotate.
				if ((gparent.left == parent) != (parent.left == node)) {
					Rotate(gparent, parent, node);
					parent = node;
				}

				gparent.IsRed = true;

				// Do a rotate to prevent two red links in a row.
				Rotate(ggparent, gparent, parent);

				parent.IsRed = false;
				rotated = true;
				return parent;
			}
			else {
				rotated = false;
				return node;
			}
		}

		/// <summary>
		/// Performs a rotation involving the node, it's child and grandchild. The counts of 
		/// childs and grand-child are set the correct values from their children; this is important
		/// if they have been adjusted on the way down the try as part of an insert/delete.
		/// </summary>
		/// <param name="node">Top node of the rotation. Can be null if child==root.</param>
		/// <param name="child">One child of "node". Not null.</param>
		/// <param name="gchild">One child of "child". Not null.</param>
		private void Rotate(Node node, Node child, Node gchild) {
			if (gchild == child.left) {
				child.left = gchild.right;
				gchild.right = child;
			}
			else {
				Debug.Assert(gchild == child.right);
				child.right = gchild.left;
				gchild.left = child;
			}

			// Restore the counts.
			child.Count = (child.left != null ? child.left.Count : 0) + (child.right != null ? child.right.Count : 0) + 1;
			gchild.Count = (gchild.left != null ? gchild.left.Count : 0) + (gchild.right != null ? gchild.right.Count : 0) + 1;

			if (node == null) {
				Debug.Assert(child == root);
				root = gchild;
			}
			else if (child == node.left) {
				node.left = gchild;
			}
			else {
				Debug.Assert(child == node.right);
				node.right = gchild;
			}
		}

		/// <summary>
		/// Deletes a key from the tree. If multiple elements are equal to key, 
		/// deletes the first or last. If no element is equal to the key, 
		/// returns false.
		/// </summary>
		/// <remarks>Top-down algorithm from Weiss. Basic plan is to move down in the tree, 
		/// rotating and recoloring along the way to always keep the current node red, which 
		/// ensures that the node we delete is red. The details are quite complex, however! </remarks>
		/// <param name="key">Key to delete.</param>
		/// <param name="deleteFirst">Which item to delete if multiple are equal to key. True to delete the first, false to delete last.</param>
		/// <param name="item">Returns the item that was deleted, if true returned.</param>
		/// <returns>True if an element was deleted, false if no element had 
		/// specified key.</returns>
		public bool Delete(T key, bool deleteFirst, out T item)
		{
			return DeleteItemFromRange(EqualRangeTester(key), deleteFirst, out item);
		}

		/// 
		/// <summary>
		/// Enumerate all the items in-order
		/// </summary>
		/// <returns>An enumerator for all the items, in order.</returns>
		/// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
		public IEnumerator<T> GetEnumerator()
		{
			return EnumerateRange(EntireRangeTester).GetEnumerator();
		}

		/// <summary>
		/// Enumerate all the items in-order
		/// </summary>
		/// <returns>An enumerator for all the items, in order.</returns>
		/// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		#region Ranges

		/// <summary>
		/// A delegate that tests if an item is within a custom range. The range must be a contiguous
		/// range of items with the ordering of this tree. The range test function must test
		/// if an item is before, withing, or after the range.
		/// </summary>
		/// <param name="item">Item to test against the range.</param>
		/// <returns>Returns negative if item is before the range, zero if item is withing the range,
		/// and positive if item is after the range.</returns>
		public delegate int RangeTester(T item);

		/// <summary>
		/// Gets a range tester that defines a range by first and last items.
		/// </summary>
		/// <param name="useFirst">If true, bound the range on the bottom by first.</param>
		/// <param name="first">If useFirst is true, the inclusive lower bound.</param>
		/// <param name="useLast">If true, bound the range on the top by last.</param>
		/// <param name="last">If useLast is true, the exclusive upper bound.</param>
		/// <returns>A RangeTester delegate that tests for an item in the given range.</returns>
		public RangeTester BoundedRangeTester(bool useFirst, T first, bool useLast, T last)
		{
			return delegate(T item) {
				if (useFirst && comparer.Compare(first, item) > 0)
					return -1;     // item is before first.
				else if (useLast && comparer.Compare(last, item) <= 0)
					return 1;      // item is after or equal to last.
				else
					return 0;      // item is greater or equal to first, and less than last.
			};
		}

		/// <summary>
		/// Gets a range tester that defines a range by first and last items.
		/// </summary>
		/// <param name="first">The lower bound.</param>
		/// <param name="firstInclusive">True if the lower bound is inclusive, false if exclusive.</param>
		/// <param name="last">The upper bound.</param>
		/// <param name="lastInclusive">True if the upper bound is inclusive, false if exclusive.</param>
		/// <returns>A RangeTester delegate that tests for an item in the given range.</returns>
		public RangeTester DoubleBoundedRangeTester(T first, bool firstInclusive, T last, bool lastInclusive)
		{
			return delegate(T item) {
				if (firstInclusive) {
					if (comparer.Compare(first, item) > 0)
						return -1;     // item is before first.
				}
				else {
					if (comparer.Compare(first, item) >= 0)
						return -1;     // item is before or equal to first.
				}

				if (lastInclusive) {
					if (comparer.Compare(last, item) < 0)
						return 1;      // item is after last.
				}
				else {
					if (comparer.Compare(last, item) <= 0)
						return 1;      // item is after or equal to last
				}

				return 0;      // item is between first and last.
			};
		}


		/// <summary>
		/// Gets a range tester that defines a range by a lower bound.
		/// </summary>
		/// <param name="first">The lower bound.</param>
		/// <param name="inclusive">True if the lower bound is inclusive, false if exclusive.</param>
		/// <returns>A RangeTester delegate that tests for an item in the given range.</returns>
		public RangeTester LowerBoundedRangeTester(T first, bool inclusive)
		{
			return delegate(T item) {
				if (inclusive) {
					if (comparer.Compare(first, item) > 0)
						return -1;     // item is before first.
					else
						return 0;      // item is after or equal to first
				}
				else {
					if (comparer.Compare(first, item) >= 0)
						return -1;     // item is before or equal to first.
					else
						return 0;      // item is after first
				}
			};
		}


		/// <summary>
		/// Gets a range tester that defines a range by upper bound.
		/// </summary>
		/// <param name="last">The upper bound.</param>
		/// <param name="inclusive">True if the upper bound is inclusive, false if exclusive.</param>
		/// <returns>A RangeTester delegate that tests for an item in the given range.</returns>
		public RangeTester UpperBoundedRangeTester(T last, bool inclusive)
		{
			return delegate(T item) {
				if (inclusive) {
					if (comparer.Compare(last, item) < 0)
						return 1;      // item is after last.
					else
						return 0;      // item is before or equal to last.
				}
				else {
					if (comparer.Compare(last, item) <= 0)
						return 1;      // item is after or equal to last
					else
						return 0;      // item is before last.
				}
			};
		}

		/// <summary>
		/// Gets a range tester that defines a range by all items equal to an item.
		/// </summary>
		/// <param name="equalTo">The item that is contained in the range.</param>
		/// <returns>A RangeTester delegate that tests for an item equal to <paramref name="equalTo"/>.</returns>
		public RangeTester EqualRangeTester(T equalTo)
		{
			return delegate(T item) {
				return comparer.Compare(item, equalTo);
			};
		}

		/// <summary>
		/// A range tester that defines a range that is the entire tree.
		/// </summary>
		/// <param name="item">Item to test.</param>
		/// <returns>Always returns 0.</returns>
		public int EntireRangeTester(T item)
		{
			return 0;
		}

		/// <summary>
		/// Enumerate the items in a custom range in the tree. The range is determined by 
		/// a RangeTest delegate.
		/// </summary>
		/// <param name="rangeTester">Tests an item against the custom range.</param>
		/// <returns>An IEnumerable&lt;T&gt; that enumerates the custom range in order.</returns>
		/// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
		public IEnumerable<T> EnumerateRange(RangeTester rangeTester)
		{
			return EnumerateRangeInOrder(rangeTester, root);
		}

		/// <summary>
		/// Enumerate all the items in a custom range, under and including node, in-order.
		/// </summary>
		/// <param name="rangeTester">Tests an item against the custom range.</param>
		/// <param name="node">Node to begin enumeration. May be null.</param>
		/// <returns>An enumerable of the items.</returns>
		/// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
		private IEnumerable<T> EnumerateRangeInOrder(RangeTester rangeTester, Node node)
		{
			int startStamp = changeStamp;

			if (node != null) {
				int compare = rangeTester(node.item);

				if (compare >= 0) {
					// At least part of the range may lie to the left.
					foreach (T item in EnumerateRangeInOrder(rangeTester, node.left)) {
						yield return item;
						CheckEnumerationStamp(startStamp);
					}
				}

				if (compare == 0) {
					// The item is within the range.
					yield return node.item;
					CheckEnumerationStamp(startStamp);
				}

				if (compare <= 0) {
					// At least part of the range lies to the right.
					foreach (T item in EnumerateRangeInOrder(rangeTester, node.right)) {
						yield return item;
						CheckEnumerationStamp(startStamp);
					}
				}
			}
		}

		/// <summary>
		/// Enumerate the items in a custom range in the tree, in reversed order. The range is determined by 
		/// a RangeTest delegate.
		/// </summary>
		/// <param name="rangeTester">Tests an item against the custom range.</param>
		/// <returns>An IEnumerable&lt;T&gt; that enumerates the custom range in reversed order.</returns>
		/// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
		public IEnumerable<T> EnumerateRangeReversed(RangeTester rangeTester)
		{
			return EnumerateRangeInReversedOrder(rangeTester, root);
		}

		/// <summary>
		/// Enumerate all the items in a custom range, under and including node, in reversed order.
		/// </summary>
		/// <param name="rangeTester">Tests an item against the custom range.</param>
		/// <param name="node">Node to begin enumeration. May be null.</param>
		/// <returns>An enumerable of the items, in reversed oreder.</returns>
		/// <exception cref="InvalidOperationException">The tree has an item added or deleted during the enumeration.</exception>
		private IEnumerable<T> EnumerateRangeInReversedOrder(RangeTester rangeTester, Node node)
		{
			int startStamp = changeStamp;

			if (node != null) {
				int compare = rangeTester(node.item);

				if (compare <= 0) {
					// At least part of the range lies to the right.
					foreach (T item in EnumerateRangeInReversedOrder(rangeTester, node.right)) {
						yield return item;
						CheckEnumerationStamp(startStamp);
					}
				}

				if (compare == 0) {
					// The item is within the range.
					yield return node.item;
					CheckEnumerationStamp(startStamp);
				}

				if (compare >= 0) {
					// At least part of the range may lie to the left.
					foreach (T item in EnumerateRangeInReversedOrder(rangeTester, node.left)) {
						yield return item;
						CheckEnumerationStamp(startStamp);
					}
				}
			}
		}


		/// <summary>
		/// Deletes either the first or last item from a range, as identified by a RangeTester
		/// delegate. If the range is empty, returns false.
		/// </summary>
		/// <remarks>Top-down algorithm from Weiss. Basic plan is to move down in the tree, 
		/// rotating and recoloring along the way to always keep the current node red, which 
		/// ensures that the node we delete is red. The details are quite complex, however! </remarks>
		/// <param name="rangeTester">Range to delete from.</param>
		/// <param name="deleteFirst">If true, delete the first item from the range, else the last.</param>
		/// <param name="item">Returns the item that was deleted, if true returned.</param>
		/// <returns>True if an element was deleted, false if the range is empty.</returns>
		public bool DeleteItemFromRange(RangeTester rangeTester, bool deleteFirst, out T item)
		{
			Node node;			// The current node.
			Node parent;		// Parent of the current node.
			Node gparent;		// Grandparent of the current node.
			Node sib;			// Sibling of the current node.
			Node keyNode;		// Node with the key that is being removed.

			// The tree may be changed.
			StopEnumerations();

			if (root == null) {
				// Nothing in the tree. Go home now.
				item = default(T);
				return false;
			}

			// We decrement counts on the way down the tree. If we end up not finding an item to delete
			// we need a stack to adjust the counts back. 
			Node[] nodeStack = GetNodeStack();
			int nodeStackPtr = 0;  // first free item on the stack.

			// Start at the root.
			node = root;
			sib = parent = gparent = null;
			keyNode = null;

			// Proceed down the tree, making the current node red so it can be removed.
			for (; ; ) {
				Debug.Assert(parent == null || parent.IsRed);
				Debug.Assert(sib == null || !sib.IsRed);
				Debug.Assert(!node.IsRed);

				if ((node.left == null || !node.left.IsRed) && (node.right == null || !node.right.IsRed)) {
					// node has two black children (null children are considered black).
					if (parent == null) {
						// Special case for the root.
						Debug.Assert(node == root);
						node.IsRed = true;
					}
					else if ((sib.left == null || !sib.left.IsRed) && (sib.right == null || !sib.right.IsRed)) {
						// sib has two black children.
						node.IsRed = true;
						sib.IsRed = true;
						parent.IsRed = false;
					}
					else {
						if (parent.left == node && (sib.right == null || !sib.right.IsRed)) {
							// sib has a black child on the opposite side as node.
							Node tleft = sib.left;
							Rotate(parent, sib, tleft);
							sib = tleft;
						}
						else if (parent.right == node && (sib.left == null || !sib.left.IsRed)) {
							// sib has a black child on the opposite side as node.
							Node tright = sib.right;
							Rotate(parent, sib, tright);
							sib = tright;
						}

						// sib has a red child.
						Rotate(gparent, parent, sib);
						node.IsRed = true;
						sib.IsRed = true;
						sib.left.IsRed = false;
						sib.right.IsRed = false;

						sib.DecrementCount();
						nodeStack[nodeStackPtr - 1] = sib;
						parent.DecrementCount();
						nodeStack[nodeStackPtr++] = parent;
					}
				}

				// Compare the key and move down the tree to the correct child.
				do {
					Node nextNode, nextSib;		// Node we've moving to, and it's sibling.

					node.DecrementCount();
					nodeStack[nodeStackPtr++] = node;

					// Determine which way to move in the tree by comparing the 
					// current item to what we're looking for.
					int compare = rangeTester(node.item);

					if (compare == 0) {
						// We've found the node to remove. Remember it, then keep traversing the
						// tree to either find the first/last of equal keys, and if needed, the predecessor
						// or successor (the actual node to be removed).
						keyNode = node;
						if (deleteFirst) {
							nextNode = node.left; nextSib = node.right;
						}
						else {
							nextNode = node.right; nextSib = node.left;
						}
					}
					else if (compare > 0) {
						nextNode = node.left; nextSib = node.right;
					}
					else {
						nextNode = node.right; nextSib = node.left;
					}

					// Have we reached the end of our tree walk?
					if (nextNode == null)
						goto FINISHED;

					// Move down the tree.
					gparent = parent;
					parent = node;
					node = nextNode;
					sib = nextSib;
				} while (!parent.IsRed && node.IsRed);

				if (!parent.IsRed) {
					Debug.Assert(!node.IsRed);
					// moved to a black child.
					Rotate(gparent, parent, sib);

					sib.DecrementCount();
					nodeStack[nodeStackPtr - 1] = sib;
					parent.DecrementCount();
					nodeStack[nodeStackPtr++] = parent;

					sib.IsRed = false;
					parent.IsRed = true;
					gparent = sib;
					sib = (parent.left == node) ? parent.right : parent.left;
				}
			}

		FINISHED:
			if (keyNode == null) {
				// We never found a node to delete.

				// Return counts back to their previous value.
				for (int i = 0; i < nodeStackPtr; ++i)
					nodeStack[i].IncrementCount();

				// Color the root black, in case it was colored red above.
				if (root != null)
					root.IsRed = false;

				item = default(T);
				return false;
			}

			// Return the item from the node we're deleting.
			item = keyNode.item;

			// At a leaf or a node with one child which is a leaf. Remove the node.
			if (keyNode != node) {
				// The node we want to delete is interior. Move the item from the
				// node we're actually deleting to the key node.
				keyNode.item = node.item;
			}

			// If we have one child, replace the current with the child, otherwise,
			// replace the current node with null.
			Node replacement;
			if (node.left != null) {
				replacement = node.left;
				Debug.Assert(!node.IsRed && replacement.IsRed);
				replacement.IsRed = false;
			}
			else if (node.right != null) {
				replacement = node.right;
				Debug.Assert(!node.IsRed && replacement.IsRed);
				replacement.IsRed = false;
			}
			else
				replacement = null;

			if (parent == null) {
				Debug.Assert(root == node);
				root = replacement;
			}
			else if (parent.left == node)
				parent.left = replacement;
			else {
				Debug.Assert(parent.right == node);
				parent.right = replacement;
			}

			// Color the root black, in case it was colored red above.
			if (root != null)
				root.IsRed = false;

			// Update item count.
			count -= 1;

			// And we're done.
			return true;
		}

		/// <summary>
		/// Delete all the items in a range, identified by a RangeTester delegate.
		/// </summary>
		/// <param name="rangeTester">The delegate that defines the range to delete.</param>
		/// <returns>The number of items deleted.</returns>
		public int DeleteRange(RangeTester rangeTester)
		{
			bool deleted;
			int counter = 0;
			T dummy;

			do {
				deleted = DeleteItemFromRange(rangeTester, true, out dummy);
				if (deleted)
					++counter;
			} while (deleted);

			return counter;
		}

		/// <summary>
		/// Count the items in a custom range in the tree. The range is determined by 
		/// a RangeTester delegate.
		/// </summary>
		/// <param name="rangeTester">The delegate that defines the range.</param>
		/// <returns>The number of items in the range.</returns>
		public int CountRange(RangeTester rangeTester)
		{
			return CountRangeUnderNode(rangeTester, root, false, false);
		}

		/// <summary>
		/// Count all the items in a custom range, under and including node.
		/// </summary>
		/// <param name="rangeTester">The delegate that defines the range.</param>
		/// <param name="node">Node to begin enumeration. May be null.</param>
		/// <param name="belowRangeTop">This node and all under it are either in the range or below it.</param>
		/// <param name="aboveRangeBottom">This node and all under it are either in the range or above it.</param>
		/// <returns>The number of items in the range, under and include node.</returns>
		private int CountRangeUnderNode(RangeTester rangeTester, Node node, bool belowRangeTop, bool aboveRangeBottom)
		{
			if (node != null) {
				if (belowRangeTop && aboveRangeBottom) {
					// This node and all below it must be in the range. Use the predefined count.
					return node.Count;
				}

				int compare = rangeTester(node.item);
				int counter;

				if (compare == 0) {
					counter = 1;  // the node itself
					counter += CountRangeUnderNode(rangeTester, node.left, true, aboveRangeBottom);
					counter += CountRangeUnderNode(rangeTester, node.right, belowRangeTop, true);
				}
				else if (compare < 0) {
					counter = CountRangeUnderNode(rangeTester, node.right, belowRangeTop, aboveRangeBottom);
				}
				else { // compare > 0
					counter = CountRangeUnderNode(rangeTester, node.left, belowRangeTop, aboveRangeBottom);
				}

				return counter;
			}
			else {
				return 0;
			}
		}

		/// <summary>
		/// Find the first item in a custom range in the tree, and it's index. The range is determined
		/// by a RangeTester delegate.
		/// </summary>
		/// <param name="rangeTester">The delegate that defines the range.</param>
		/// <param name="item">Returns the item found, if true was returned.</param>
		/// <returns>Index of first item in range if range is non-empty, -1 otherwise.</returns>
		public int FirstItemInRange(RangeTester rangeTester, out T item)
		{
			Node node = root, found = null;
			int curCount = 0, foundIndex = -1;

			while (node != null) {
				int compare = rangeTester(node.item);

				if (compare == 0) {
					found = node;
					if (node.left != null)
						foundIndex = curCount + node.left.Count;
					else
						foundIndex = curCount;
				}

				if (compare >= 0)
					node = node.left;
				else {
					if (node.left != null)
						curCount += node.left.Count + 1;
					else
						curCount += 1;
					node = node.right;
				}
			}

			if (found != null) {
				item = found.item;
				return foundIndex;
			}
			else {
				item = default(T);
				return -1;
			}
		}

		/// <summary>
		/// Find the last item in a custom range in the tree, and it's index. The range is determined
		/// by a RangeTester delegate.
		/// </summary>
		/// <param name="rangeTester">The delegate that defines the range.</param>
		/// <param name="item">Returns the item found, if true was returned.</param>
		/// <returns>Index of the item if range is non-empty, -1 otherwise.</returns>
		public int LastItemInRange(RangeTester rangeTester, out T item)
		{
			Node node = root, found = null;
			int curCount = 0, foundIndex = -1;

			while (node != null) {
				int compare = rangeTester(node.item);

				if (compare == 0) {
					found = node;
					if (node.left != null)
						foundIndex = curCount + node.left.Count;
					else
						foundIndex = curCount;
				}

				if (compare <= 0) {
					if (node.left != null)
						curCount += node.left.Count + 1;
					else
						curCount += 1;
					node = node.right;
				}
				else
					node = node.left;
			}

			if (found != null) {
				item = found.item;
				return foundIndex;
			}
			else {
				item = default(T);
				return foundIndex;
			}
		}

		#endregion Ranges

#if DEBUG
		/// <summary>
		/// Prints out the tree.
		/// </summary>
		public void Print() {
			PrintSubTree(root, "", "");
			Console.WriteLine();
		}

		/// <summary>
		/// Prints a sub-tree.
		/// </summary>
		/// <param name="node">Node to print from</param>
		/// <param name="prefixNode">Prefix for the node</param>
		/// <param name="prefixChildren">Prefix for the node's children</param>
		private void PrintSubTree(Node node, string prefixNode, string prefixChildren) {
			if (node == null)
				return;

			// Red nodes marked as "@@", black nodes as "..".
			Console.WriteLine("{0}{1} {2,4} {3}", prefixNode, node.IsRed ? "@@" : "..", node.Count, node.item);

			PrintSubTree(node.left, prefixChildren + "|-L-", prefixChildren + "|  ");
			PrintSubTree(node.right, prefixChildren + "|-R-", prefixChildren + "   ");
		}

		/// <summary>
		/// Validates that the tree is correctly sorted, and meets the red-black tree 
		/// axioms.
		/// </summary>
		public void Validate() {
			Debug.Assert(comparer != null, "Comparer should not be null");

			if (root == null) {
				Debug.Assert(0 == count, "Count in empty tree should be 0.");
			
			}
			else {
				Debug.Assert(! root.IsRed, "Root is not black");
				int blackHeight;
				int nodeCount = ValidateSubTree(root, out blackHeight);
				Debug.Assert(nodeCount == this.count, "Node count of tree is not correct.");
			}
		}

		/// <summary>
		/// Validates a sub-tree and returns the count and black height.
		/// </summary>
		/// <param name="node">Sub-tree to validate. May be null.</param>
		/// <param name="blackHeight">Returns the black height of the tree.</param>
		/// <returns>Returns the number of nodes in the sub-tree. 0 if node is null.</returns>
		private int ValidateSubTree(Node node, out int blackHeight) {
			if (node == null) {
				blackHeight = 0;
				return 0;
			}

			// Check that this node is sorted with respect to any children.
			if (node.left != null)
				Debug.Assert(comparer.Compare(node.left.item, node.item) <= 0, "Left child is not less than or equal to node");
			if (node.right != null)
				Debug.Assert(comparer.Compare(node.right.item, node.item) >= 0, "Right child is not greater than or equal to node");

			// Check that the two-red rule is not violated.
			if (node.IsRed) {
				if (node.left != null)
					Debug.Assert(! node.left.IsRed, "Node and left child both red");
				if (node.right != null) 
					Debug.Assert(! node.right.IsRed, "Node and right child both red");
			}

			// Validate sub-trees and get their size and heights.
			int leftCount, leftBlackHeight;
			int rightCount, rightBlackHeight;
			int ourCount;

			leftCount = ValidateSubTree(node.left, out leftBlackHeight);
			rightCount = ValidateSubTree(node.right, out rightBlackHeight);
			ourCount = leftCount + rightCount + 1;

			Debug.Assert(ourCount == node.Count);

			// Validate the equal black-height rule.
			Debug.Assert(leftBlackHeight == rightBlackHeight, "Black heights are not equal");

			// Calculate our black height and return the count
			blackHeight = leftBlackHeight;
			if (! node.IsRed)
				blackHeight += 1;
			return ourCount;
		}
#endif //DEBUG

	}

}
